home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
476-500
/
disk_500
/
wiconify
/
wutilities.lzh
/
wIconClock
/
wIconClock.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-04-19
|
20KB
|
728 lines
/*
* WICONCLOCK A utility that works with WICONIFY to display a
* clock icon on every wIconify screen. The clock face
* shows the current time, and updates as time passes.
*
* Copyright 1990 by Davide P. Cervone, all rights reserved.
* You may use this code, provided this copyright notice is kept intact.
*/
#define INTUITION_PREFERENCES_H /* don't need 'em */
#include <intuition/intuitionbase.h>
#include <devices/timer.h>
#include <libraries/dos.h>
#include "wIcon.h"
static char *Program = "wIconClock v1.1";
static char *Copyright =
"Copyright (c) 1990 by Davide P. Cervone, all rights reserved";
struct IntuitionBase *IntuitionBase;
#define INTUITION_REV 0
#define DELAYSECS 1 /* How often to look for time changes */
#define DELAYMICS 0
#define MAXSCREENS 24 /* Largest number of screens expected */
#define STANDARD_TIME 1 /* 12 hour clock with AM/PM */
#define MILITARY_TIME 2 /* 24 hour clock */
#define EXIT_OK 0L
#define EXIT_ERROR 10L
#define REPORTFLAGS WI_REPORTOPEN| WI_REPORTCLOSE| WI_REPORTAUTOREMOVE
/*
* Clock face image size
*/
#define CLOCKWIDTH 40
#define CLOCKHEIGHT 19
#define CLOCKDEPTH 2
#define WORDSPERROW 3
static struct timerequest TimerRequest; /* Timer IO request */
static struct MsgPort *TimerPort; /* Timer IO reply port */
static int TimerOpen; /* TRUE if timer open */
static int TimerSet; /* TRUE if request pending */
static int OldPri; /* Old process priority */
static APTR ClockTask; /* Pointer to this task */
static int TimeType = STANDARD_TIME; /* Time display type */
/*
* The clock face image data area
*/
extern USHORT ClockData[CLOCKDEPTH][CLOCKHEIGHT*WORDSPERROW];
/*
* The clock icon name area
*/
static char ClockName[] = "00:00 AM";
/*
* The clock icon's image structure
*/
static struct Image ClockImage =
{0,0, CLOCKWIDTH,CLOCKHEIGHT,CLOCKDEPTH, &ClockData[0][0], 0x03,0, NULL};
/*
* The clock icon definition
*/
static WICON ClockIcon =
{&ClockName[0], &ClockImage, NULL,NULL,
600,15, WI_AUTOREMOVE| WI_NOORGANIZE, REPORTFLAGS, NULL};
static short ClockX,ClockY;
static WICONREF *Clock[MAXSCREENS]; /* wIconRefs of all open clocks */
static WICONREF *NewScreenClock; /* Clock receiving NEWSCREEN reports */
static int ClockCount; /* How many are open */
extern WICONREF *wAddIcon();
/*
* HandData tells how to draw each hand. Offset says how far to change
* the x position from our current position, and count says how many
* pixels in a row to use. {0,0} ends the list.
*/
struct HandData {BYTE Offset,Count;};
/*
* The big hand has sixty positions, but these are brocken down into
* four sets (15 minute chuncks) which are symmetric either by a
* flip horizontally, vertically, or both.
*/
static struct HandData BigHand[16][6] =
{
{{-1,2},{-1,2},{-1,2},{-2,4},{-2,4},{-1,2}},
{{-1,2},{-1,2},{-1,3},{-1,3},{-1,3},{0,2}},
{{-1,2},{-1,2},{-1,3},{-1,4},{0,3},{1,2}},
{{-1,2},{-1,3},{0,3},{0,4},{1,3},{2,2}},
{{-1,2},{0,2},{1,3},{1,4},{2,4},{4,1}},
{{-1,2},{0,3},{1,4},{2,4},{4,3},{0,0}},
{{-1,2},{0,3},{2,3},{3,4},{6,3},{0,0}},
{{-1,2},{1,2},{3,3},{5,4},{7,3},{0,0}},
{{-1,2},{1,3},{3,5},{6,4},{0,0},{0,0}},
{{-1,3},{2,3},{4,4},{7,3},{0,0},{0,0}},
{{-1,4},{2,4},{5,3},{8,2},{0,0},{0,0}},
{{-1,5},{4,5},{7,5},{0,0},{0,0},{0,0}},
{{-1,6},{3,7},{9,4},{0,0},{0,0},{0,0}},
{{-1,5},{4,8},{0,0},{0,0},{0,0},{0,0}},
{{-1,9},{8,5},{0,0},{0,0},{0,0},{0,0}},
{{-1,14},{0,0},{0,0},{0,0},{0,0},{0,0}}
};
/*
* The little hand has positions for each hour and half-hour, and
* are brocken down in the same way as the big hand.
*/
static struct HandData LittleHand[7][6] =
{
{{-1,2},{-1,2},{-2,4},{-1,2},{0,0},{0,0}},
{{-1,2},{-1,3},{-1,3},{0,2},{0,0},{0,0}},
{{-1,2},{0,3},{1,3},{2,2},{0,0},{0,0}},
{{-1,3},{0,4},{2,3},{0,0},{0,0},{0,0}},
{{-1,3},{1,4},{3,4},{0,0},{0,0},{0,0}},
{{-1,5},{2,5},{0,0},{0,0},{0,0},{0,0}},
{{-1,9},{0,0},{0,0},{0,0},{0,0},{0,0}}
};
/*
* FreeClocks()
*
* For each clock in the clock array, remove the clock icon from the
* screen, and clear its array position. Decrement the clock count as
* we go.
*/
static void FreeClocks()
{
short i;
for (i=0; i<MAXSCREENS && ClockCount; i++)
{
if (Clock[i]) wRemoveIcon(Clock[i]);
Clock[i] = NULL;
ClockCount--;
}
}
/*
* Print()
*
* Find the standard AmigaDOS output file and write the output string
* to the output file. This is intended as a substitute for printf()
* when no formatting is required, and when you want a small executable.
*/
static void Print(s)
char *s;
{
ULONG OutFile;
extern ULONG Output();
OutFile = Output();
if (OutFile && s) Write(OutFile,s,strlen(s));
}
/*
* DoExit()
*
* Print an error message, if one is give, and set the return status.
* Return the task priority to normal, and clean up any memory or
* other resources that were allocated.
* Exit with the correct return status.
*/
static void DoExit(message)
char *message;
{
int status = EXIT_OK;
if (message)
{
Print(message);
Print("\n");
status = EXIT_ERROR;
}
SetTaskPri(ClockTask,OldPri);
if (TimerSet) AbortIO(&(TimerRequest.tr_node));
if (TimerOpen) CloseDevice(&TimerRequest);
if (TimerPort) DeletePort(TimerPort);
if (ClockCount) FreeClocks();
if (ClockIcon.IconPort) DeletePort(ClockIcon.IconPort);
if (IntuitionBase) CloseLibrary(IntuitionBase);
_exit(status);
}
#define ISSPACE(x) (x == ' ' || x == '\t')
#define NOTSPACE(x) (x != '\0' && x != ' ' && x != '\t')
/*
* ParseArgs()
*
* If there was a parameter line,
* Skip the command (which is the first thing on the line).
* Skip any trailing spaces.
* Find the end-of-line and remove the new-line character and any
* trailing blanks.
* While there is more one the line
* Find the first space (ie, the end of the word).
* Mark the end of the word and skip any trailing spaces.
* If the word is one of the time specifiers, save the type,
* Otherwise, if the word is a position X,Y then save the position,
* Otherwise exit with the usage message.
* Continue looking at the rest of the line.
*/
static void ParseArgs(line)
char *line;
{
char *s;
int X,Y;
if (line)
{
while (ISSPACE(*line)) line++;
while (NOTSPACE(*line)) line++;
while (ISSPACE(*line)) line++;
for (s = line; *s && *s != '\n'; s++);
if (*s) *s = 0; if (s > line) while (*(--s) == ' ') *s = 0;
while (*line)
{
s = line; while (NOTSPACE(*s)) s++;
if (*s)
{
*s++ = 0;
while (ISSPACE(*s)) s++;
}
if (stricmp(line,"MILITARY") == 0) TimeType = MILITARY_TIME; else
if (stricmp(line,"STANDARD") == 0) TimeType = STANDARD_TIME; else
if (sscanf(line,"%ld,%ld",&X,&Y) == 2)
ClockX = X, ClockY = Y;
else DoExit("Usage: wIconClock [MILITARY | STANDARD] [x,y]");
line = s;
}
}
}
/*
* CheckLibOpen()
*
* Call OpenLibrary() for the specified library, and check that the
* open succeeded.
*/
static void CheckLibOpen(lib,name,rev)
APTR *lib;
char *name;
int rev;
{
extern APTR OpenLibrary();
if ((*lib = OpenLibrary(name,(ULONG)rev)) == NULL)
DoExit("Can't Open Library");
}
/*
* SetupClock()
*
* Get a pointer to the clock task (the current task) and change the
* task priority to 5 (so we update the screen a little faster).
* Get a port for the clock icons, if possible.
* Get a reply port for the timer requests, if possible.
* Open the timer device, and initialize the timer request.
*/
static void SetupClock()
{
extern struct MsgPort *CreatePort();
extern APTR FindTask();
ClockTask = FindTask(NULL);
OldPri = SetTaskPri(ClockTask,5);
ClockIcon.IconPort = CreatePort(0,0);
if (ClockIcon.IconPort == NULL) DoExit("Can't Create Icon Port\n");
TimerPort = CreatePort(0,0);
if (TimerPort == NULL) DoExit("Can't Create Timer Port\n");
if (OpenDevice(TIMERNAME,UNIT_VBLANK,&TimerRequest,0) != NULL)
DoExit("Can't Open Timer Device");
TimerRequest.tr_node.io_Message.mn_ReplyPort = TimerPort;
TimerRequest.tr_node.io_Command = TR_ADDREQUEST;
TimerRequest.tr_node.io_Flags = 0;
TimerOpen = TRUE;
}
/*
* UpdateTime()
*
* Set the time string to the proper characters for the specified
* time display type. Trim the initial zero if the hour is only
* one digit long.
*/
static void UpdateTime(s,h,m)
char s[];
short h,m;
{
switch(TimeType)
{
case STANDARD_TIME:
s[5] = ' ';
s[6] = (h >= 12)? 'P': 'A';
h = h % 12; if (h == 0) h = 12;
break;
case MILITARY_TIME:
s[5] = 0;
break;
}
s[0] = '0' + (h / 10);
s[1] = '0' + (h % 10);
s[2] = ':';
s[3] = '0' + (m / 10);
s[4] = '0' + (m % 10);
if (s[0] == '0') s++;
ClockIcon.Name = s;
}
/*
* UpdateHand()
*
* dx and dy specify the direction we are moving on the clock face,
* Hand is the hand array of the particular position we are using,
* SetIt specifies whether we are adding or removing the hand.
*
* Start at the center of the clock.
* For each {offset,count} pair,
* Get the offset and count.
* If there is anything to do,
* Set the mask to the correct number of bits.
* Shift the mask by the correct offset for the dx direction.
* Divide the mask into three parts (one for each word in a row of
* the clock image data).
* If we are adding the had, clear those bits (to make the pen color 2)
* Otherwise set them (to make the pen color 3).
* Increment the y position in the correct direction.
*/
static void UpdateHand(dx,dy,Hand,SetIt)
short dx,dy;
struct HandData *Hand;
int SetIt;
{
short y = (CLOCKHEIGHT-1)/2 * WORDSPERROW;
short i;
ULONG mask;
UWORD m1,m2,m3;
short count,offset;
for (i=0; i<6; i++)
{
count = Hand[i].Count;
offset = Hand[i].Offset;
if (count)
{
mask = ((1 << count) - 1);
mask <<= (dx < 0)? (16 + offset): (16 - count - offset);
m1 = mask >> (CLOCKWIDTH/2);
m2 = (mask >> (16 - (32-(CLOCKWIDTH/2)))) & 0xFFFF;
m3 = (mask << (32-(CLOCKWIDTH/2)) ) & 0xFFFF;
if (SetIt)
{
ClockData[0][y] &= ~m1;
ClockData[0][y+1] &= ~m2;
ClockData[0][y+2] &= ~m3;
} else {
ClockData[0][y] |= m1;
ClockData[0][y+1] |= m2;
ClockData[0][y+2] |= m3;
}
}
y += dy;
}
}
/*
* UpdateFace()
*
* Get the proper quadrant for the position of the big hand for the current
* time, and update the big hand.
* Now get the correct quadrant for the little hand:
* shift the minutes by 15 mintes since we want the little hand to
* change at a quarter after and a quarter of - that way the be one the
* hour from a quarter of to a quarter after, and on the half hour from
* a quarter after to a quarter to.
* Take the hour modulo 12 and multiply by two (every other hand is the
* hour position). If the minutes are in the half-hour range, increment
* to the half-hour position.
* Finally, reduce by quadrants, as before.
* Update the clock face.
*/
static void UpdateFace(h,m,SetIt)
short h,m;
int SetIt;
{
short dx,dy;
short m1 = m;
dx = 1; dy = -WORDSPERROW;
if (m > 30) m -= 30, dx = -1, dy = WORDSPERROW;
if (m > 15) m = 30 - m, dy = -dy;
UpdateHand(dx,dy,&BigHand[m][0],SetIt);
m1 += 15; if (m1 >= 60) m1 -= 60, h++;
h %= 12; h *= 2; if (m1 > 29) h++;
dx = 1; dy = -WORDSPERROW;
if (h > 12) h -= 12, dx = -1, dy = WORDSPERROW;
if (h > 6) h = 12 - h, dy = -dy;
UpdateHand(dx,dy,&LittleHand[h][0],SetIt);
}
/*
* UpdateClocks()
*
* Clear the clock position so the icons will remain where they are.
* For each clock that has been openned,
* Update the clock to the new face iamge,
* If the clock is the one receiving NEWSCREEN reports, add its report flags.
*/
static void UpdateClocks()
{
short i,count;
ClockIcon.x = ClockIcon.y = 0;
for (i=0, count=ClockCount; i<MAXSCREENS && count; i++)
{
if (Clock[i])
{
wUpdateIcon(Clock[i],&ClockIcon); count--;
if (Clock[i] == NewScreenClock)
wModifyReport(Clock[i],REPORTFLAGS | WI_REPORTNEWSCREEN);
}
}
}
/*
* SetNewScreenClock()
*
* We only want one clock to report NEWSCREEN events, otherwise we would
* be adding too many new clocks as new screens open (one for each clock
* already open). So only the first clock in the list is marked to
* receive NEWSCREEN message.
*
* Skip any blank array elements, and if we have found a clock,
* mark it to receive NEWSCREEN messages.
*/
static void SetNewScreenClock()
{
short i;
for (i=0; i<MAXSCREENS && Clock[i] == NULL; i++);
if (i < MAXSCREENS)
{
wModifyReport(Clock[i],REPORTFLAGS | WI_REPORTNEWSCREEN);
NewScreenClock = Clock[i];
}
}
/*
* FinishClock()
*
* Look through the clock list for the given clock,
* If found,
* Clear the array element for re-use, and cancel the loop.
* Decrement the clock count, and if this is the last one, we're done.
* If the clock was the one receiving NEWSCREEN messages, we need to choose
* another one to get them.
*/
static int FinishClock(theClock)
WICONREF *theClock;
{
short i;
int NotDone = TRUE;
for (i=0; i<MAXSCREENS; i++)
{
if (Clock[i] == theClock)
{
Clock[i] = NULL; i = MAXSCREENS;
if (--ClockCount == 0) NotDone = FALSE; else
if (theClock == NewScreenClock) SetNewScreenClock();
}
}
return(NotDone);
}
/*
* NewClock()
*
* If we can add more clocks,
* Look through the clock array for an open spot.
* If we found a spot,
* Set the clock position: if it was specified on the command line,
* use that, otherwise back it near the upper right.
* Add the clock to the new screen.
* If the add was successful, increment the clock count.
* End the search loop.
*/
static void NewClock(theScreen)
struct Screen *theScreen;
{
short i;
if (ClockCount < MAXSCREENS)
{
for (i=0; i<MAXSCREENS; i++)
{
if (Clock[i] == NULL)
{
if (ClockX || ClockY)
{
ClockIcon.x = ClockX;
ClockIcon.y = ClockY;
} else {
ClockIcon.x = theScreen->Width - CLOCKWIDTH - 12;
ClockIcon.y = 15;
}
Clock[i] = wAddIcon(theScreen,&ClockIcon);
if (Clock[i]) ClockCount++;
i = MAXSCREENS;
}
}
}
}
/*
* CreateClocks()
*
* Look through the Intuition screen list, and save the screen
* pointers (we do this because we don't want te list to change while
* we're looking at it, but we can't add icons as we go, since we
* will enter a Wait() state which may allow other tasks to change
* the screen list).
* For each pointer found, try to add a clock the that screen.
* Get a clock to receive NEWSCREEN messages.
*/
static void CreateClocks()
{
struct Screen *Screen[MAXSCREENS];
struct Screen *theScreen;
short i = 0;
int ILock;
ILock = LockIBase(0L);
theScreen = IntuitionBase->FirstScreen;
while (theScreen)
{
Screen[i++] = theScreen;
theScreen = theScreen->NextScreen;
}
UnlockIBase(ILock);
while (i--) NewClock(Screen[i]);
SetNewScreenClock();
}
/*
* WaitForAction()
*
* Wait for the messages from the timer or the icon port.
* While there are still clock icons on screen,
* Get the datestamp, and recover the hours and minutes.
* If the time has changed since the last check,
* Remove the old hands and add the new ones.
* Update all the clocks to use the new faces.
* Save the time of the last update.
* Of no timer request is pending,
* Set up the timer request and send it.
* Mark that a requet is pending (in case we need to remove it later).
*
* Wait for the timer or icon message.
* If the timer message was returned, mark it so we can re-issue it.
* For each icon message we receive, do the right thing:
* OPEN: change the display format when the user double-clicks the
* clock icon, and unselect the icon. Only change if the
* icons is actually selected (to avoid changing during OPENALL
* commands).
* CLOSE: remove the icon if the user closes it.
* AUTOREMOVE: wIconify removed the icon when it closed the screen.
* In either casem we check to make sure it was not the NEWSCREEN
* icon, and if so, choose another.
* NEWSCREEN: try to open a new clock icon on the new screen.
* Then reply to the message.
*/
static void WaitForAction()
{
short Hours,Mins;
short OldH = 0, OldM = 0;
struct DateStamp theDateStamp;
ULONG Signals;
int NotDone = TRUE;
struct wIconMessage *theMessage;
extern struct wIconMessage *GetMsg();
Signals = (1 << TimerPort->mp_SigBit)| (1 << ClockIcon.IconPort->mp_SigBit);
while (NotDone)
{
DateStamp(&theDateStamp);
Hours = theDateStamp.ds_Minute / 60;
Mins = theDateStamp.ds_Minute % 60;
if (Hours != OldH || Mins != OldM)
{
UpdateFace(OldH,OldM,FALSE);
UpdateFace(Hours,Mins,TRUE);
UpdateTime(ClockName,Hours,Mins);
UpdateClocks();
OldH = Hours; OldM = Mins;
}
if (TimerSet == FALSE)
{
TimerRequest.tr_time.tv_secs = DELAYSECS;
TimerRequest.tr_time.tv_micro = DELAYMICS;
SendIO(&(TimerRequest.tr_node));
TimerSet = TRUE;
}
Wait(Signals);
while (GetMsg(TimerPort)) TimerSet = FALSE;
while (theMessage = GetMsg(ClockIcon.IconPort))
{
switch(theMessage->Action)
{
case WI_REPORTOPEN:
if (wIconFlags(theMessage->Icon) & WI_SELECTED)
{
TimeType = (MILITARY_TIME + STANDARD_TIME) - TimeType;
OldH = OldM = 0;
wUnSelectIcon(theMessage->Icon);
}
break;
case WI_REPORTCLOSE:
wRemoveIcon(theMessage->Icon);
case WI_REPORTAUTOREMOVE:
NotDone = FinishClock(theMessage->Icon);
break;
case WI_REPORTNEWSCREEN:
NewClock(theMessage->Data.Screen);
break;
}
ReplyMsg(theMessage);
}
}
}
/*
* _main()
*
* Replaces the standard Lattice C _main routine. It receives the
* complete command line as a single string as its only argument.
*
* Parse the argument list.
* If wIconify is active,
* Open Intuition.
* Set up the ports and timer stuff.
* Create the clocks for the existing screens.
* If there were any clocks created, wait for them to be closed,
* Otherwise, say that none could be created.
* Exit with no error.
* Otherwise, say wIconify is not running.
*/
void _main(line)
char *line;
{
ParseArgs(line);
if (wIconifyActive())
{
CheckLibOpen(&IntuitionBase,"intuition.library",INTUITION_REV);
SetupClock();
CreateClocks();
if (ClockCount) WaitForAction();
else Print("Can't create Clock Icons on any Screen\n");
DoExit(NULL);
} else {
Print("wIconify not running or incompatible version\n");
}
}